package com.cleargroup.magic.cleara.c.command;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;

import com.aa.base.PlayerCheck;

import java.io.File;
import java.util.Arrays;



public class StoreManager extends StoreManagerQueryHelper {
    private static final String TAG = StoreManager.class.getSimpleName();
    private static final boolean DEBUG = PlayerCheck.isDebugMode();

    private static final String INTERNAL_VOLUMN = "internal";
    private static final String EXTERNAL_VOLUMN = "external";
    private static final Uri FILES_URI = MediaStore.Files.getContentUri(EXTERNAL_VOLUMN);
    private static final Uri THUMBNAILS_URI = MediaStore.Images.Thumbnails.getContentUri(EXTERNAL_VOLUMN);
    public static final String TARGET_PATH = EnvironmentUtil.EXTERNAL_STORAGE + "/easyWifiManager/systembackup/";


    //ROM Storage pattern, in order to exclude true external storage in clean result
    private static final String[] STORAGE_PATTERNS = {"%" + EnvironmentUtil.EXTERNAL_STORAGE + "%"};
    // TEMP_PATTERN = Pattern.compile("[^a-zA-Z0-9](cache|caches|tmp|temp[^a-zA-Z0-9])");
    // TEMP_PATTERN2 = Pattern.compile("(cache|caches|tmp|temp)[^a-zA-Z0-9]");
    // LOG_PATTERN = Pattern.compile("[^a-zA-Z0-9](log|logs)[^a-zA-Z0-9]");
    private static final String[] TEMP_PATTERNS = {
            "%/cache%",     "%cache/%",     "%.cache%",     "%cache.%",     "%-cache%",    "%cache-%",          //"%/_cache% escape '/'",        "%cache/_% escape '/'",
            "%/tmp%",        "%tmp/%",       "%.tmp%",       "%tmp.%",       "%-tmp%",      "%tmp-%",
            "%/temp%",       "%temp/%",      "%.temp%",      "%temp.%",      "%-temp%",     "%temp-%",
            "%/log",          "%log/%",       "%.log",        "%log.%",       "%-log%",      "%log-%",
    };
    // THUMB_PATTERN = Pattern.compile("[^a-zA-Z0-9](thumbnails|iconcache|imgcache|imagecache)");
    private static final String[] THUMB_PATTERNS = {"%thumbnails%", "%iconcache%", "%imgcache%", "%imagecache%"};
    // LOG_PATTERN = Pattern.compile("[^a-zA-Z0-9](log|logs)[^a-zA-Z0-9]");
    private static final String[] APK_PATTERNS = {"%.apk"};
    // size=0
    private static final String[] EMPTY_PATTERNS = {"0"};
    // DCIM thumbnails
    private static final String[] DCIM_PATTERNS = {"%/DCIM/.thumbnails%"};
    // DATA == filepath
    private static final String[] PROJECTIONS_DATA = {DATA};

    private static final String[] TOOLBOX_SYSTEM_PATTERNS = {"%" + TARGET_PATH + "%"};


    private static StoreManager mInstance;
    private boolean mIsComplete;
    private boolean mCanceled;
    private Context mContext;
    private int mTotalSize;
    private int mCurrentSize;

    private StoreManager(Context context) {
        mContext = context;
    }

    public static StoreManager get(Context context) {
        if (mInstance == null) {
            mInstance = new StoreManager(context);
        }
        return mInstance;
    }

    public Context getContext() {
        return mContext;
    }

    public boolean isCanceled() {
        return mCanceled;
    }

    public void setCanceled(boolean canceled) {
        this.mCanceled = canceled;
    }

    private boolean query(Uri uri, String[] projections, SelectionParam selection, String sortOrder, int type, ScanManageListener listener) {
        if (DEBUG) Log.i(TAG, "SM::query ======================= " + type);
        if (DEBUG) Log.i(TAG, "SM::query selection " + selection.selection);
        if (DEBUG) Log.i(TAG, "SM::query args " + Arrays.toString(selection.selectionArgs));

        ContentResolver cr = getContext().getContentResolver();
        Cursor cursor = cr.query(uri, projections, selection.selection, selection.selectionArgs, sortOrder);
        if(cursor == null) {
            return false;
        }

        int column = cursor.getColumnIndex(StoreManager.DATA);
        mTotalSize = cursor.getCount();
        mCurrentSize =  0;
        try {
            if (DEBUG) Log.i(TAG, "SM::query " + uri + ", " + mTotalSize);
            for (int i = 0; cursor.moveToNext() && !isCanceled(); i++) {
                if(i == mTotalSize - 1) {
                    setComplete(true);
                } else {
                    setComplete(false);
                }

                File file = new File(cursor.getString(column));
                if (!file.canRead()) {
                    continue;
                }

                if (type == TrashHelper.TRASH_EMPTY) {
                    if (!isEmptyFolder(file)) {
                        continue;
                    }
                }

                if (listener != null) {
                    mCurrentSize++;
                    listener.onNodeScan(type, file);
                }
            }
        } catch (Throwable ignored) {

        } finally {
            ReleaseUtil.release(cursor);
        }
        return  mTotalSize>0 ;
    }

    public long getTotalProgress() {
        long res = -1;
        if(mInstance != null) {
            res = mInstance.mTotalSize;
        }
        return res;
    }

    public long getCurrentProgress() {
        long res = -1;
        if(mInstance != null) {
            res = mInstance.mCurrentSize;
        }
        return res;
    }

    private boolean queryData(Uri uri, SelectionParam selection, String sortOrder, int type, ScanManageListener listener) {
        return query(uri, PROJECTIONS_DATA, selection, sortOrder, type, listener);
    }

    private boolean queryEmulated(Uri uri, SelectionParam selection, String sortOrder, int type, ScanManageListener listener) {
        //限定于虚拟存储路径（Emulated == Environment.getExternalStorageDirectory）
        SelectionParam likeEmulated = new SelectionParam(paren(dataLikeX()), STORAGE_PATTERNS);
        SelectionParam newSelection = new SelectionParam(likeEmulated, selection);
        return queryData(uri, newSelection, sortOrder, type, listener);
    }

    private boolean queryWithIgnores(Uri uri, SelectionParam selection, String sortOrder, int type, ScanManageListener listener) {
        //排除忽略列表路径
        String[] ignores = new String[]{};
        SelectionParam notLikeIgnores = new SelectionParam(dataNotLikeX(ignores), ignores);
        SelectionParam newSelection = new SelectionParam(selection, notLikeIgnores);
        return queryEmulated(uri, newSelection, sortOrder, type, listener);
    }

    private boolean isEmptyFolder(File file) {
        boolean res = false;

        if (file != null && file.canRead()) {
            String[] subs = file.list();
            if (subs != null && subs.length == 0) {
                res = true;
            }
        }

        return res;
    }

    public void queryTrash(ScanManageListener listener) {
        SelectionParam likeTemp = new SelectionParam(dataLikeX(TEMP_PATTERNS), TEMP_PATTERNS);
        SelectionParam notThumb = new SelectionParam(dataNotLikeX(THUMB_PATTERNS), THUMB_PATTERNS);
        SelectionParam notApk = new SelectionParam(dataNotLikeX(APK_PATTERNS), APK_PATTERNS);
        SelectionParam selection = new SelectionParam(likeTemp, notThumb, notApk);
        queryWithIgnores(FILES_URI, selection, null, TrashHelper.TRASH_TEMPERARY, listener);
    }

    // force query path
    public void queryTrash(ScanManageListener listener, String path) {
        String[] pathArgs = new String[]{path + "%"};
        SelectionParam likePath = new SelectionParam(dataLikeX(pathArgs), pathArgs);

        SelectionParam likeTemp = new SelectionParam(dataLikeX(TEMP_PATTERNS), TEMP_PATTERNS);
        SelectionParam notThumb = new SelectionParam(dataNotLikeX(THUMB_PATTERNS), THUMB_PATTERNS);
        SelectionParam notApk = new SelectionParam(dataNotLikeX(APK_PATTERNS), APK_PATTERNS);
        SelectionParam selection = new SelectionParam(likePath, likeTemp, notThumb, notApk);
        queryEmulated(FILES_URI, selection, null, TrashHelper.TRASH_TEMPERARY, listener);
    }

    public void queryThumb(ScanManageListener listener) {
        SelectionParam likeThumb = new SelectionParam(dataLikeX(THUMB_PATTERNS), THUMB_PATTERNS);
        SelectionParam notApk = new SelectionParam(dataNotLikeX(APK_PATTERNS), APK_PATTERNS);
        SelectionParam notDcim = new SelectionParam(dataNotLikeX(DCIM_PATTERNS), DCIM_PATTERNS);
        SelectionParam selection = new SelectionParam(likeThumb, notApk);
        boolean ret = queryWithIgnores(THUMBNAILS_URI, selection, null, TrashHelper.TRASH_THUMBNAIL, listener);
        //THUMBNAILS_URI 空，查/Dcim
        if(!ret){
            queryWithIgnores(FILES_URI, selection, null, TrashHelper.TRASH_THUMBNAIL, listener);
        }
        //THUMBNAILS_URI 非空，不查/Dcim
        else {
            SelectionParam selection2 = new SelectionParam(likeThumb, notApk, notDcim);
            queryWithIgnores(FILES_URI, selection2, null, TrashHelper.TRASH_THUMBNAIL, listener);
        }
    }

    // force query path
    public void queryThumb(ScanManageListener listener, String path) {
        String[] pathArgs = new String[]{path + "%"};
        SelectionParam likePath = new SelectionParam(dataLikeX(pathArgs), pathArgs);

        SelectionParam likeThumb = new SelectionParam(dataLikeX(THUMB_PATTERNS), THUMB_PATTERNS);
        SelectionParam notApk = new SelectionParam(dataNotLikeX(APK_PATTERNS), APK_PATTERNS);
        SelectionParam notDcim = new SelectionParam(dataNotLikeX(DCIM_PATTERNS), DCIM_PATTERNS);
        SelectionParam selection = new SelectionParam(likePath, likeThumb, notApk);
        boolean ret = queryEmulated(THUMBNAILS_URI, selection, null, TrashHelper.TRASH_THUMBNAIL, listener);
        if(!ret){
            queryEmulated(FILES_URI, selection, null, TrashHelper.TRASH_THUMBNAIL, listener);
        }  else {
            SelectionParam selection2 = new SelectionParam(likeThumb, notApk, notDcim);
            queryEmulated(FILES_URI, selection2, null, TrashHelper.TRASH_THUMBNAIL, listener);
        }
    }

    // /sdcard/Android/data/xxx/cache
//    public void queryCacheOnStorage(ScanManageListener listener) {
//    }
//
//    public void queryLeftover(ScanManageListener listener) {
//    }

    public void queryApk(ScanManageListener listener) {
        SelectionParam likeApk = new SelectionParam(dataLikeX(APK_PATTERNS), APK_PATTERNS);
        queryWithIgnores(FILES_URI, likeApk, null, TrashHelper.TRASH_APK, listener);
    }

    // force query path
    public void queryApk(ScanManageListener listener, String path) {
        String[] pathArgs = new String[]{path + "%"};
        SelectionParam likePath = new SelectionParam(dataLikeX(pathArgs), pathArgs);

        SelectionParam likeApk = new SelectionParam(dataLikeX(APK_PATTERNS), APK_PATTERNS);
        queryEmulated(FILES_URI, new SelectionParam(likePath, likeApk), null, TrashHelper.TRASH_APK, listener);
    }


    //empty folders in db may contains files not scanned by MediaStore
    public void queryEmpty(ScanManageListener listener) {
        String emptySql = paren(SIZE + "=?" + and() + columnNotInColumn(_ID, PARENT));
        SelectionParam likeEmpty = new SelectionParam(emptySql, EMPTY_PATTERNS);
        queryWithIgnores(FILES_URI, likeEmpty, null, TrashHelper.TRASH_EMPTY, listener);
    }

    // force query path
    public void queryEmpty(ScanManageListener listener, String path) {
        String[] pathArgs = new String[]{path + "%"};
        SelectionParam likePath = new SelectionParam(dataLikeX(pathArgs), pathArgs);

        String emptySql = paren(SIZE + "=?" + and() + columnNotInColumn(_ID, PARENT));
        SelectionParam likeEmpty = new SelectionParam(emptySql, EMPTY_PATTERNS);
        queryEmulated(FILES_URI, new SelectionParam(likePath, likeEmpty), null, TrashHelper.TRASH_EMPTY, listener);
    }

    public void queryLarge(long fileSize, ScanManageListener listener) {
        String largeSql = SIZE + ">?";
        String[] largeSize = new String[]{String.valueOf(fileSize)};
        SelectionParam selection = new SelectionParam(largeSql, largeSize);
        queryWithIgnores(FILES_URI, selection, SIZE, TrashHelper.TRASH_LARGEFILE, listener);
    }

    private void setComplete(boolean complete) {
        mIsComplete = complete;
    }

    public boolean isCompele() {
        return mIsComplete;
    }

    private static class SelectionParam {
        String selection = "";
        String[] selectionArgs = null;

        SelectionParam(String selection, String[] selectionArgs) {
            this.selection = selection;
            this.selectionArgs = selectionArgs;
        }

        SelectionParam(SelectionParam... selectionParams) {
            int length = selectionParams.length;

            if(length > 0) {
                for (int i = 0; i < length; i++) {
                    SelectionParam sp = selectionParams[i];
                    if (i < length - 1) {
                        selection += sp.selection + and();
                    } else {
                        selection += sp.selection;
                    }
                    selectionArgs = concatArrays(selectionArgs, sp.selectionArgs);
                }
            }

            if(DEBUG) Log.i(TAG, "SM::SelectionParam " + selection);
            if(DEBUG) Log.i(TAG, "SM::SelectionParam " + Arrays.toString(selectionArgs));
        }
    }
}
